from . import passport_bp
from flask import current_app, jsonify, session
from flask import request, abort
from info import constants, db
from info import redis_store
from info.utils.captcha.captcha import captcha
from info.utils.response_code import RET
import re
from info.models import User
from info.lib.yuntongxin.sms import CCP
import random
from datetime import datetime


@passport_bp.route("/image_code")
def get_image_code():
    """获取验证码图片"""
    # 1.获取参数
    # 1.1获取前端传过来的随机编码
    imageCodeId = request.args.get("imageCodeId")

    # 2.校验参数
    # 2.2 UUID编码 判断是否为空
    if not imageCodeId:
        abort(404)

    # 3.逻辑处理
    # 3.1 生成验证码图片对象 ,取得验证码的真实值
    name, text, image = captcha.generate_captcha()

    try:
        redis_store.set("imagecode_%s" % imageCodeId, text, ex=constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        abort(500)

    # 4.返回值处理
    # 4.1 将图片对象返回给前端展示
    return image


@passport_bp.route("/sms_code", methods=["POST"])
def send_sms():
    """点击发送短信验证码接口"""
    """
    1.获取参数
      1.1 获取从前端传过来的用户手机号码,随机编码,还有用户填写的验证码内容
    2.校验参数
      2.1 判断随机编码,手机号码,用户填写的内容是否为空
      2.2 验证手机号码格式是否正确
    3.逻辑处理
      3.1 根据用户的随机编码从redis中取出图形验证码的真实值
      3.1.1 判断取出来的值是否为空 为空则代表验证码已经过期  细节: 让前端再给用户发一张图形验证码
      3.1.2 不为空则把redis中存储的这个真实值删掉 预防这个值被仿佛使用
      3.2 比较用户填写的值和存储在redis中的这个值是否相等
      3.2.1 不相等提示用户该验证码不正确 让前端给用户再发送一张图形验证码
      3.2.2 相等就可以发送短信验证码
      3.3 在发送短信验证码之前先拿到用户的手机号判断该手机号之前是否已经注册过
      3.3.1 注册过提示用户已经注册过
      3.3.2 之前没注册过就可以调用云通信模板给用户发送短信验证码
      3.4 生成6位的验证码 不够6位在前面补0
      3.5 发送短信验证码成功 保存在redis中
    4.返回值处理
    """
    # 1.1 获取从前端传过来的用户手机号码,随机编码,还有用户填写的验证码内容
    param_dict = request.json
    mobile = param_dict.get("mobile")
    image_code = param_dict.get("image_code")
    image_code_id = param_dict.get("image_code_id")

    # 2.1 判断随机编码是否为空
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")
    # 2.2 验证手机号码格式是否正确
    if not re.match("1[35689][0-9]{9}", mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机格式错误")

    # 3.1根据用户的随机编码从redis中取出图形验证码的真实值
    try:
        real_image_code = redis_store.get("imagecode_%s" % image_code_id)

        # 3.1.1不为空则把redis中存储的这个真实值删掉 预防这个值被反复使用
        if real_image_code:
            redis_store.delete("imagecode_%s" % image_code_id)
    except Exception as e:
        current_app.logger(e)
        return jsonify(errno=RET.DBERR, errmsg="查询验证码的真实值异常")
    # 3.1.2判断取出来的值是否为空 为空则代表验证码已经过期
    if not real_image_code:
        return jsonify(errno=RET.NODATA, errmsg="验证码过期")
    # 3.2 比较用户填写的值和存储在redis中的这个值是否相等
    if image_code.lower() != real_image_code.lower():
        return jsonify(errno=RET.DATAERR, errmsg="验证码填写错误")
    try:
        user = User.query.filter_by(mobile=mobile).first()
        if user:
            return jsonify(errno=RET.DATAEXIST, errmsg="该手机号已经注册")
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")
    # 3.3 调用云通讯模板进行发送短信验证码
    # 3.3.1 生成6位随机内容
    # sms_code = random.randint(0, 999999)
    # sms_code = "%06d" % sms_code
    sms_code = 160424
    result = CCP().send_template_sms(mobile, [sms_code, constants.IMAGE_CODE_REDIS_EXPIRES / 6], 1)

    if result != 0:
        return jsonify(errno=RET.THIRDERR, errmsg="发送短信验证码失败")

    try:
        redis_store.set("SMS_%s" % mobile, sms_code, ex=constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="保存短信到数据库异常")
    return jsonify(errno=RET.OK, errmsg="发送短信验证码成功")


# 在创建蓝图的时候已经加上前缀passport
@passport_bp.route("/register", methods=["POST"])
def register():
    """注册接口"""
    """
    1. 获取参数
      1.1 获取从前端传过来的手机号,短信验证码,密码
    2. 校验参数
      2.1 判断这些参数是否都不为空
      2.2 判断手机格式是否正确 预防有些用户填写完图形验证码后改掉手机号码
    3. 逻辑处理
      3.1 根据编码去redis中取得真实的短信验证码
      3.2 一致就把该手机号码存到数据库中
      3.3 不一致提示用户短信验证码填写错误 让前端再给用户再发一条短信验证码
      3.4 注册也算登录成功一次 使用session记录用户的登录记录
    4. 返回值处理
    """
    # 1.1 获取从前端传过来的手机号,短信验证码,密码
    params_dict = request.json
    mobile = params_dict.get("mobile")
    smscode = params_dict.get("smscode")
    password = params_dict.get("password")
    # 判断非空操作
    if not all([mobile, smscode, password]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不够")

    # 校验手机格式是否正确
    if not re.match("1[356789]\d{9}", mobile):
        return jsonify(RET.PARAMERR, errmsg="手机格式不正确")
    # 3.1 根据编码去redis中取得真实的短信验证码
    try:
        real_sms_code = redis_store.get("SMS_%s" % mobile)
        if real_sms_code:
            redis_store.delete("SMS_%s" % mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取真实短信验证码失败")
    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg="短信验证码过期")

    # 3.2 比较真实短信验证码和用户填写的验证码是否一致
    if real_sms_code != smscode:
        return jsonify(errno=RET.DATAERR, errmsg="短信验证码填写错误")

    # 3.3 一致:创建用户对象给里面的属性赋值,存储到数据库中User表中
    # 创建用户对象给属性赋值
    user = User()
    user.nick_name = mobile
    user.mobile = mobile
    # TODO:对密码进行赋值(加密)
    user.password = password

    # 获取当前时间最为最后一次登录时间
    user.last_login = datetime.now()
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 数据库回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="添加用户到数据库 失败")
    # 3.4 一般注册成功就代表你有登录过一次,可以使用session记录登录状态
    session["user_id"] = user.id
    session["nick_name"] = user.nick_name
    session["mobile"] = user.mobile

    # 4.返回注册成功的响应
    return jsonify(errno=RET.OK, errmsg="注册成功")


@passport_bp.route("/login", methods=["POST"])
def login():
    """登录接口"""
    """
    1. 获取参数
        1.1获取手机号码,密码(未加密)
    2. 校验参数
        2.1 非空判断
        2.2 手机格式校验
    3. 逻辑处理
        3.1 根据手机号码查询用户对象
        3.2 对比用户填写的密码和数据库中存储的短信验证码是否一致
        3.3 一致 记录最后一次登录时间 使用session记录用户登录信息
    4. 返回值处理
    """
    # 1.1获取手机号码,密码(未加密)
    params_dict = request.json
    mobile = params_dict.get("mobile")
    password = params_dict.get("password")

    # 2.1 非空判断
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    # 2.2 手机格式校验
    if not re.match("1[35689]\d{9}", mobile):
        return jsonify(errno=RET.PARAMERR, errmsg="手机格式错误")
    # 3.1 根据手机号码查询用户对象
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询用户对象异常")
    if not user:
        return jsonify(errno=RET.NODATA, errmsg="用户不存在")

    # 3.2 对比用户填写的密码和数据库中存储的短信验证码是否一致
    if not user.check_passowrd(password):
        return jsonify(errno=RET.DATAERR, errmsg="密码填写错误")

    # 3.3 一致:记录最后一次登录时间 使用session记录用户登录信息
    session["user_id"] = user.id
    session["mobile"] = user.mobile
    session["nick_name"] = user.nick_name

    # 修改最后一次登录时间
    user.last_login = datetime.now()

    # 当修改了模型身上的属性的时候 不需要add只需要commit即可
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="用户存储信息失败")
    return jsonify(errno=RET.OK, errmsg="登录成功")


@passport_bp.route("/login_out", methods=["POST"])
def login_out():
    """退出登录接口"""
    # 清除session保存的用户信息
    session.pop("user_id")
    session.pop("mobile")
    session.pop("nick_name")
    return jsonify(errno=RET.OK, errmsg="退出登录成功")

    # @passport_bp.route('/login_out', methods=["POST"])
    # def login_out():
    #     """退出登录接口"""
    #
    #     # 清除session保存的用户信息
    #     session.pop("user_id")
    #     session.pop("mobile")
    #     session.pop("nick_name")
    #
    #     return jsonify(errno=RET.OK, errmsg="退出登录成功")
